package common.correspondence;

import common.Port;
import common.proto.out.CountMessage;

import java.io.*;
import java.net.InetAddress;
import java.net.ServerSocket;
import java.net.Socket;
import java.net.SocketException;
import java.nio.ByteBuffer;
import java.util.Arrays;
import java.util.LinkedList;
import java.util.List;

import static common.correspondence.Client.*;

public class Server extends Thread{
    String name;

    ServerSocket s;
    Port port;
    InetAddress ip;
    int socketPort;
    int _c;

    List<Thread> th;
    List<Socket> socketList;
    InputStream is;
    InputStreamReader isr;
    BufferedReader br;

    public Server(InetAddress ip, int socketPort, Port port){
        super();
        name = String.format("%s server", port.name);
        _c = 0;
        this.socketPort = socketPort;
        this.port = port;
        this.ip = ip;
        socketList = new LinkedList<>();
        th = new LinkedList<>();
        try {
            this.s = new ServerSocket(socketPort, 50, ip);
            this.start();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    public void close(){
        try {
            if(s!=null){
                for(Socket socket:socketList){
                    if(!socket.isClosed())
                        socket.close();
                }
                this.s.close();
                this.is.close();
//                this.isr.close();
            }
            for(Thread t:th){
                t.interrupt();
            }

        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    public boolean isAlready(){
        return this.s != null && !this.s.isClosed();
    }
    public void run() {
        try {
            Socket so = s.accept();
//            if(socket != null && !socket.isClosed()) socket.close();
//            socket = so;
            socketList.add(so);
            Thread t = new Thread(this);
            t.start();
            Thread.currentThread().setName(String.format("%s-%s", name, _c++));
            th.add(Thread.currentThread());
            is = so.getInputStream();
            byte[] header = new byte[8];
            byte[] start_tag = new byte[4];
            while (true) {
                boolean flag = false;
                int headerRead = 0;
                if(is.read(start_tag) >=0 && Arrays.equals(start_tag, MESSAGE_START_TAG)){
                    int readLen;
                    while (headerRead < 8){
                        readLen = is.read(header, headerRead, 8- headerRead);
                        if(readLen == -1) {
                            System.err.println("shut while read");
                            flag = true;
                            break;
                        };
                        headerRead += readLen;
                    }
                    if (flag) break;
                    long time = System.nanoTime();
                    int type = byteArrayToInt(header, 0);
                    int length = byteArrayToInt(header, 4);
//                    CountMessage.CountResult countResult = CountMessage.CountResult.parseDelimitedFrom(is);
//                    is.close();
                    int rec = 0;
                    byte[] content = new byte[length];
                    while(rec < length){
                        readLen = is.read(content, rec, length-rec);
                        if(readLen == -1) {
                            System.err.println("shut while read");
                            flag = true;
                            break;
                        }
                        rec += readLen;
                    }
                    if (flag) break;

                    Message msg = new Message(type, content);
                    msg.receiveTime = time;
                    msg.source = port.portName;
                    port.receive(msg);
                }else break;
            }

        } catch (SocketException ignored){

        }catch (IOException e) {
            e.printStackTrace();
            port.device.printf("%s连接异常\n", name);
        }
    }

    public static int byteArrayToInt(byte[] bytes, int start) {
        int value=0;
        for(int i = 0; i < 4; i++) {
            value <<= 8;
            value |= (bytes[start+i] & 0xFF);
        }
        return value;
    }
}
